﻿using System;
using System.Collections.Generic;
using NPOI.SS.UserModel;

namespace Jaiden.Data.Exporting
{
    public class NPOIExcelExportTarget : IExportTarget
    {
        private readonly IWorkbook _workbook;
        private ICellStyle _dateTimeCellStyle;

        private IFont _headerCellFont;
        private ICellStyle _headerCellStyle;

        public NPOIExcelExportTarget(IWorkbook workbook)
        {
            _workbook = workbook;
        }

        public void Export<T>(IEnumerable<T> data, IExportRole<T> role)
        {
            var sheet = _workbook.GetSheet(role.Name) ?? _workbook.CreateSheet(role.Name);

            var header = sheet.CreateRow(0);
            for (var i = 0; i < role.Columns.Count; i++)
            {
                var col = role.Columns[i];
                var cell = header.CreateCell(i);
                cell.SetCellType(CellType.String);
                cell.SetCellValue(col.Name);
                cell.CellStyle = GetHeaderCellStyle();

                if (col.ValueType == typeof(DateTime))
                    sheet.SetColumnWidth(i, 16 * 256);
                else
                    sheet.SetColumnWidth(i, 10 * 256);
            }

            var rownum = 1;
            foreach (var item in data)
            {
                var row = sheet.CreateRow(rownum);
                for (var i = 0; i < role.Columns.Count; i++)
                {
                    var cell = row.CreateCell(i);
                    SetCellValue(cell, role.Columns[i].ValueGetter(item));
                }

                rownum++;
            }
        }

        protected virtual ICellStyle GetHeaderCellStyle()
        {
            if (_headerCellStyle == null)
            {
                _headerCellStyle = _workbook.CreateCellStyle();
                _headerCellStyle.Alignment = HorizontalAlignment.Center;
                _headerCellFont = _workbook.CreateFont();
                _headerCellFont.FontHeightInPoints = 10;
                _headerCellFont.Boldweight = 700;
                _headerCellStyle.SetFont(_headerCellFont);
            }

            return _headerCellStyle;
        }

        protected virtual ICellStyle GetDateTimeCellStyle()
        {
            if (_dateTimeCellStyle == null)
            {
                _dateTimeCellStyle = _workbook.CreateCellStyle();

                var format = _workbook.CreateDataFormat();
                _dateTimeCellStyle.DataFormat = format.GetFormat("yyyy-mm-dd HH:mm");
            }

            return _dateTimeCellStyle;
        }

        protected virtual void SetCellValue(ICell cell, object value)
        {
            if (value == null || value == DBNull.Value)
            {
                cell.SetCellValue(string.Empty);
                return;
            }

            if (value is string)
            {
                cell.SetCellValue((string) value);
                cell.SetCellType(CellType.String);
            }
            else if (value is DateTime)
            {
                if ((DateTime) value != default) cell.SetCellValue((DateTime) value);
                cell.CellStyle = GetDateTimeCellStyle();
            }
            else if (value is bool)
            {
                cell.SetCellValue((bool) value);
                cell.SetCellType(CellType.Boolean);
            }
            else if (value is short || value is int || value is long || value is byte || value is decimal ||
                     value is float || value is double)
            {
                cell.SetCellValue(Convert.ToDouble(value));
                cell.SetCellType(CellType.Numeric);
            }
            else
            {
                cell.SetCellValue(value.ToString());
            }
        }
    }
}